#ifndef __CVECTOR4D_H__
#define __CVECTOR4D_H__

#include "StdDefs.h"
#include "CMathFixed.h"
#include "CVector3d.h"



// CVector4d* must maintain casting ability with (fixed*).
// CVector4d may not have virtuals, inherited, or instantiated data.


class CVector4d
{
public:
	CVector4d(){}
	CVector4d( const fixed* ijkw );
	CVector4d( fixed i, fixed j, fixed k, fixed w );
	CVector4d( const CVector4d& v );
	~CVector4d(){}

	fixed				Length() const;

	CVector4d&			Clear();
	CVector4d&			Set( fixed i, fixed j, fixed k, fixed w );
	CVector4d&			Set( const CVector4d& v );
	CVector4d&			Normalize();

	CVector4d&			operator=( const fixed* ijkw );
	CVector4d&			operator=( const CVector3d& v );

	CVector4d&			operator+=( const CVector4d& v );
	CVector4d&			operator+=( fixed val );
	CVector4d&			operator-=( const CVector4d& v );
	CVector4d&			operator-=( fixed val );
	CVector4d&			operator*=( fixed val );
	CVector4d&			operator/=( fixed val );

	fixed&				operator[]( uint32 idx );
	fixed				operator[]( uint32 idx ) const;

	__inline operator	fixed const*() const { return &m_i; }
	__inline operator	fixed*() { return &m_i; }

	friend CVector4d	operator+( const CVector4d& v1, const CVector4d& v2 );
	friend CVector4d	operator+( const CVector4d& v, fixed val );
	friend CVector4d	operator+( fixed val, const CVector4d& v );
	friend CVector4d	operator-( const CVector4d& v1, const CVector4d& v2 );
	friend CVector4d	operator-( const CVector4d& v, fixed val );
	friend CVector4d	operator-( fixed val, const CVector4d& v );
	friend fixed		operator*( const CVector4d& v1, const CVector4d& v2 );
	friend CVector4d	operator*( const CVector4d& v, fixed val );
	friend CVector4d	operator*( fixed val, const CVector4d& v );
	friend CVector4d	operator/( const CVector4d& v, fixed val );
	friend CVector4d	operator/( fixed val, const CVector4d& v );
	
	fixed				m_i; 
	fixed				m_j;
	fixed				m_k;
	fixed				m_w;
};


 
 

inline 
CVector4d::CVector4d( fixed i, fixed j, fixed k, fixed w )
{ 
	m_i = i; 
	m_j = j; 
	m_k = k; 
	m_w = w; 
}


inline 
CVector4d::CVector4d( const CVector4d& v )
{
	m_i = v.m_i; 
	m_j = v.m_j; 
	m_k = v.m_k; 
	m_w = v.m_w; 
}


inline
fixed CVector4d::Length() const
{
	return CMathFixed::Sqrt( ( *this * *this ) );
}


inline
CVector4d& CVector4d::Clear()
{
	m_i = 0; 
	m_j = 0;
	m_k = 0;
	m_w = 0;

	return *this;
}


inline
CVector4d& CVector4d::Set( fixed i, fixed j, fixed k, fixed w )
{
	m_i = i; 
	m_j = j;
	m_k = k;
	m_w = w;

	return *this;
}


inline 
CVector4d& CVector4d::Set( const CVector4d& v )
{
	m_i = v.m_i; 
	m_j = v.m_j; 
	m_k = v.m_k; 
	m_w = v.m_w;

	return *this;
}


inline
CVector4d& CVector4d::Normalize()
{
	fixed len = Length();

	if( len )
		*this /= len;

	return *this;
}


inline
fixed& CVector4d::operator[]( uint32 idx )
{
	ASSERT( idx < 4 );

	return *( ( (fixed*)this ) + idx );
}


inline
fixed CVector4d::operator[]( uint32 idx ) const
{
	ASSERT( idx < 4 );

	return *( ( (fixed*)this ) + idx );
}


inline 
CVector4d operator+( const CVector4d& v1, const CVector4d& v2 )
{ 
	return CVector4d( v1.m_i + v2.m_i, v1.m_j + v2.m_j, v1.m_k + v2.m_k, v1.m_w + v2.m_w ); 
}


inline 
CVector4d operator+( const CVector4d& v, fixed val )
{ 
	return CVector4d( v.m_i + val, v.m_j + val, v.m_k + val, v.m_w + val ); 
}


inline 
CVector4d operator+( fixed val, const CVector4d& v )
{ 
	return CVector4d( val + v.m_i, val + v.m_j, val + v.m_k, val + v.m_w ); 
}


inline 
CVector4d operator-( const CVector4d& v1, const CVector4d& v2 )
{ 
	return CVector4d( v1.m_i - v2.m_i,  v1.m_j - v2.m_j, v1.m_k - v2.m_k, v1.m_w - v2.m_w ); 
}


inline 
CVector4d operator-( const CVector4d& v, fixed val )
{ 
	return CVector4d( v.m_i - val, v.m_j - val, v.m_k - val, v.m_w - val ); 
}


inline 
CVector4d operator-( fixed val, const CVector4d& v )
{ 
	return CVector4d( val - v.m_i, val - v.m_j, val - v.m_k, val - v.m_w ); 
}


inline
fixed operator*( const CVector4d& v1, const CVector4d& v2 )
{
	return CMathFixed::Mul( v1.m_i, v2.m_i ) + CMathFixed::Mul( v1.m_j, v2.m_j ) + 
		   CMathFixed::Mul( v1.m_k, v2.m_k ) + CMathFixed::Mul( v1.m_w, v2.m_w );
}


inline
CVector4d operator*( const CVector4d& v, fixed val )
{
	return CVector4d( CMathFixed::Mul( v.m_i, val ), CMathFixed::Mul( v.m_j, val ),
					  CMathFixed::Mul( v.m_k, val ), CMathFixed::Mul( v.m_w, val ) );
}


inline
CVector4d operator*( fixed val, const CVector4d& v )
{
	return CVector4d( CMathFixed::Mul( val, v.m_i ), CMathFixed::Mul( val, v.m_j ),
					  CMathFixed::Mul( val, v.m_k ), CMathFixed::Mul( val, v.m_w ) );
}


inline
CVector4d operator/( const CVector4d& v, fixed val )
{
	return CVector4d( CMathFixed::Div( v.m_i, val ), CMathFixed::Div( v.m_j, val ),
					  CMathFixed::Div( v.m_k, val ), CMathFixed::Div( v.m_w, val ) );
}


inline
CVector4d operator/( fixed val, const CVector4d& v )
{
	return CVector4d( CMathFixed::Div( val, v.m_i ), CMathFixed::Div( val, v.m_j ),
					  CMathFixed::Div( val, v.m_k ), CMathFixed::Div( val, v.m_w ) );
}


 

#endif // __CVECTOR4D_H__